/*  
  
 SHA-1   in   C  
  
 By   Steve   Reid   <steve@edmweb.com>  
  
 100%   Public   Domain  
  
  
 Test   Vectors   (from   FIPS   PUB   180-1)  
  
 "abc "  
  
 A9993E36   4706816A   BA3E2571   7850C26C   9CD0D89D  
  
 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq "  
  
 84983E44   1C3BD26E   BAAE4AA1   F95129E5   E54670F1  
  
 A   million   repetitions   of   "a "  
  
 34AA973C   D4C4DAA4   F61EEB2B   DBAD2731   6534016F  
  
 */   
  
  
/*   #define   LITTLE_ENDIAN   *   This   should   be   #define 'd   if   true.   */   
  
/*   #define   SHA1HANDSOFF   *   Copies   data   before   messing   with   it.   */   
  
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "base64.h"
#include "onvifsha1.h"

#ifndef DF_DEBUG
#define DF_DEBUG(msg, ...) printf("[ %s,%d]=> ",__FILE__,__LINE__);printf(msg);printf("\r\n");
#endif


typedef   struct  {   
    unsigned   long   state[5];       
    unsigned   long   count[2];      
    unsigned   char   buffer[64];         
}SHA1_CTX;   
    
void   SHA1Transform(unsigned   long   state[5],   unsigned   char   buffer[64]);   
void   SHA1Init(SHA1_CTX*   context);     
void   SHA1Update(SHA1_CTX*   context,   unsigned   char*   data,   unsigned   int   len);    
void   SHA1Final(unsigned   char   digest[20],   SHA1_CTX*   context);   
   
#define   rol(value,   bits)   (((value)   <<   (bits))   |   ((value)   >>   (32   -   (bits))))   
  
  
/*   blk0()   and   blk()   perform   the   initial   expand.   */     
/*   I   got   the   idea   of   expanding   during   the   round   function   from   SSLeay   */    
#ifdef   LITTLE_ENDIAN    
#define   blk0(i)   (block-> l[i]   =   (rol(block-> l[i],24)&0xFF00FF00)|(rol(block-> l[i],8)&0x00FF00FF))    
#else    
#define   blk0(i)   block-> l[i]   
#endif   
  
#define   blk(i)   (block-> l[i&15]   =   rol(block-> l[(i+13)&15]^block-> l[(i+8)&15]^block-> l[(i+2)&15]^block-> l[i&15],1))   
  
  
/*   (R0+R1),   R2,   R3,   R4   are   the   different   operations   used   in   SHA1   */   
#define   R0(v,w,x,y,z,i)   z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);    
#define   R1(v,w,x,y,z,i)   z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);    
#define   R2(v,w,x,y,z,i)   z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);    
#define   R3(v,w,x,y,z,i)   z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);   
#define   R4(v,w,x,y,z,i)   z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);   
  
/*   Hash   a   single   512-bit   block.   This   is   the   core   of   the   algorithm.   */     
void   SHA1Transform(unsigned   long   state[5],   unsigned   char   buffer[64])    
{      
	unsigned long   a,   b,   c,   d,   e;     
	typedef union   {      
	    unsigned char c[64];   
	    unsigned long l[16];    
	}CHAR64LONG16;   
	  
	CHAR64LONG16*   block;   
      
#ifdef  SHA1HANDSOFF       
    static unsigned char workspace[64];     
    block = (CHAR64LONG16*)workspace;    
    memcpy(block, buffer, 64);        
#else    
    block = (CHAR64LONG16*)buffer;     
#endif      
    /*   Copy   context-> state[]   to   working   vars   */       
    a = state[0];       
    b = state[1];     
    c = state[2];     
    d = state[3];      
    e = state[4];        
    /*   4   rounds   of   20   operations   each.   Loop   unrolled.   */    
    R0(a,b,c,d,e, 0);   R0(e,a,b,c,d, 1);   R0(d,e,a,b,c, 2);   R0(c,d,e,a,b, 3);    
    R0(b,c,d,e,a, 4);   R0(a,b,c,d,e, 5);   R0(e,a,b,c,d, 6);   R0(d,e,a,b,c, 7);     
    R0(c,d,e,a,b, 8);   R0(b,c,d,e,a, 9);   R0(a,b,c,d,e,10);   R0(e,a,b,c,d,11);    
    R0(d,e,a,b,c,12);   R0(c,d,e,a,b,13);   R0(b,c,d,e,a,14);   R0(a,b,c,d,e,15);       
    R1(e,a,b,c,d,16);   R1(d,e,a,b,c,17);   R1(c,d,e,a,b,18);   R1(b,c,d,e,a,19);      
    R2(a,b,c,d,e,20);   R2(e,a,b,c,d,21);   R2(d,e,a,b,c,22);   R2(c,d,e,a,b,23);        
    R2(b,c,d,e,a,24);   R2(a,b,c,d,e,25);   R2(e,a,b,c,d,26);   R2(d,e,a,b,c,27);       
    R2(c,d,e,a,b,28);   R2(b,c,d,e,a,29);   R2(a,b,c,d,e,30);   R2(e,a,b,c,d,31);      
    R2(d,e,a,b,c,32);   R2(c,d,e,a,b,33);   R2(b,c,d,e,a,34);   R2(a,b,c,d,e,35);        
    R2(e,a,b,c,d,36);   R2(d,e,a,b,c,37);   R2(c,d,e,a,b,38);   R2(b,c,d,e,a,39);        
    R3(a,b,c,d,e,40);   R3(e,a,b,c,d,41);   R3(d,e,a,b,c,42);   R3(c,d,e,a,b,43);       
    R3(b,c,d,e,a,44);   R3(a,b,c,d,e,45);   R3(e,a,b,c,d,46);   R3(d,e,a,b,c,47);       
    R3(c,d,e,a,b,48);   R3(b,c,d,e,a,49);   R3(a,b,c,d,e,50);   R3(e,a,b,c,d,51);       
    R3(d,e,a,b,c,52);   R3(c,d,e,a,b,53);   R3(b,c,d,e,a,54);   R3(a,b,c,d,e,55);        
    R3(e,a,b,c,d,56);   R3(d,e,a,b,c,57);   R3(c,d,e,a,b,58);   R3(b,c,d,e,a,59);     
    R4(a,b,c,d,e,60);   R4(e,a,b,c,d,61);   R4(d,e,a,b,c,62);   R4(c,d,e,a,b,63);     
    R4(b,c,d,e,a,64);   R4(a,b,c,d,e,65);   R4(e,a,b,c,d,66);   R4(d,e,a,b,c,67);       
    R4(c,d,e,a,b,68);   R4(b,c,d,e,a,69);   R4(a,b,c,d,e,70);   R4(e,a,b,c,d,71);      
    R4(d,e,a,b,c,72);   R4(c,d,e,a,b,73);   R4(b,c,d,e,a,74);   R4(a,b,c,d,e,75);     
    R4(e,a,b,c,d,76);   R4(d,e,a,b,c,77);   R4(c,d,e,a,b,78);   R4(b,c,d,e,a,79);       
    /*   Add   the   working   vars   back   into   context.state[]   */     
    state[0] += a;      
    state[1] += b;       
    state[2] += c;        
    state[3] += d;       
    state[4] += e;   
    /*   Wipe   variables   */     
    a = b = c = d = e = 0;   
      
}   
/*   SHA1Init   -   Initialize   new   context   */   
  
void   SHA1Init(SHA1_CTX* context)    
{       
    /*   SHA1   initialization   constants   */   
    context->state[0] = 0x67452301;   
    context->state[1] = 0xEFCDAB89;   
    context->state[2] = 0x98BADCFE;    
    context->state[3] = 0x10325476;     
    context->state[4] = 0xC3D2E1F0;   
    context->count[0] = context->count[1] = 0;   
    
}   
  
/*   Run   your   data   through   this.   */    
void  SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)   
{        
    unsigned int i, j;   
    j = (context->count[0] >> 3) & 63;      
    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;  
    	context->count[1] += (len >> 29);   
      
    if((j + len) > 63)
	{   
        memcpy(&context->buffer[j], data, (i = 64-j));     
        SHA1Transform(context->state, context->buffer);   
        for(; i + 63 < len; i += 64)   
		{   
            SHA1Transform(context->state, &data[i]);          
        }   
        j = 0;      
    }   
      
    else i = 0;   
      
    memcpy(&context->buffer[j], &data[i], len - i);       
}   
  
/*   Add   padding   and   return   the   message   digest.   */     
void  SHA1Final(unsigned char digest[20], SHA1_CTX* context)   
{   
    unsigned long i, j;     
    unsigned char finalcount[8];   

    for(i = 0; i < 8; i++)  
	{   
        finalcount[i] = (unsigned char)((context->count[(i >= 4?0:1)] >> ((3-(i&3))*8))&255);     /*   Endian   independent   */    
    }   

    SHA1Update(context, (unsigned char *)"\200", 1);   
      
    while((context->count[0] & 504) != 448)  
	{       
        SHA1Update(context, (unsigned char *)"\0", 1);    
    }   
      
    SHA1Update(context, finalcount, 8);     /*   Should   cause   a   SHA1Transform()   */   
      
    for(i = 0; i < 20; i++)   
	{    
        digest[i] = (unsigned char)((context->state[i>>2] >> ((3-(i&3))*8))&255);      
    }   
      
    /*   Wipe   variables   */   
    i = j = 0;   
    memset(context->buffer, 0, 64);     
    memset(context->state, 0, 20);      
    memset(context->count, 0, 8);      
    memset(&finalcount, 0,8);   
      
#ifdef  SHA1HANDSOFF     /*   make   SHA1Transform   overwrite   it 's   own   static   vars   */     
    SHA1Transform(context->state, context->buffer);   
#endif 
}   
  
#if 0  
/*************************************************************/   
int   main(int   argc,   char**   argv)   
  
{   
      
    int   i,   j;   
      
    SHA1_CTX   context;   
      
    unsigned   char   digest[20],   buffer[16384];   
      
    FILE*   file;   
      
      
    if   (argc   >   2)   {   
          
        puts( "Public   domain   SHA-1   implementation   -   by   Steve   Reid   <steve@edmweb.com> ");   
          
        puts( "Produces   the   SHA-1   hash   of   a   file,   or   stdin   if   no   file   is   specified. ");   
          
        exit(0);   
          
    }   
      
    if   (argc   <   2)   {   
          
        file   =   stdin;   
          
    }   
      
    else   {   
          
        if   (!(file   =   fopen(argv[1],   "rb ")))   {   
              
            fputs( "Unable   to   open   file. ",   stderr);   
              
            exit(-1);   
              
        }   
          
    }     
      
    SHA1Init(&context);   
      
    while   (!feof(file))   {     /*   note:   what   if   ferror(file)   */   
          
        i   =   fread(buffer,   1,   16384,   file);   
          
        SHA1Update(&context,   buffer,   i);   
          
    }   
      
    SHA1Final(digest,   &context);   
      
    fclose(file);   
      
    for   (i   =   0;   i   <   5;   i++)   {   
          
        for   (j   =   0;   j   <   4;   j++)   {   
              
            printf( "%02X ",   digest[i*4+j]);   
              
        }   
          
        putchar(' ');   
          
    }   
      
    putchar('\n');   
      
    exit(0);   
      
}   
#endif

unsigned char *OnvifClinetSHA1(unsigned char *src, unsigned long n, unsigned char *dst)
{
	SHA1_CTX context; 
	SHA1Init(&context); 
	SHA1Update(&context, src, n);
	SHA1Final(dst, &context);
	return dst;
}

unsigned char *OnvifClinetSHA1_EX(const char *created, const char *nonce, int noncelen,const char *password,unsigned char *dst)
{
	SHA1_CTX context; 
	SHA1Init(&context); 
	SHA1Update(&context, (unsigned char *)nonce,   noncelen);
	SHA1Update(&context, (unsigned char *)created, strlen(created));
	SHA1Update(&context, (unsigned char *)password,strlen(password));
	SHA1Final(dst, &context);
	return dst;
}

unsigned char *digest_auth_info(const char *usrpwd, const char *nonce_coded, const char *date, char *digest_buff, int buffsize)
{
    int  nonce_len = 0;
    char nonce[64] = {0};
    unsigned char sha1_code[64] = {0};
	
	nonce_len = Base64decode(nonce, nonce_coded);
	struct sha1_ctx sha1;
	sha1_init_ctx(&sha1);
	sha1_process_bytes(nonce, nonce_len, &sha1);
	sha1_process_bytes(date, strlen (date), &sha1);
	sha1_process_bytes(usrpwd, strlen (usrpwd), &sha1);
	sha1_finish_ctx(&sha1, sha1_code);
	Base64encode(digest_buff, sha1_code, 20);
	return digest_buff;
}

